﻿using System;
using AiFrame.InterfaceLib;
using AiFrame.InterfaceLib.Data.Patterns;
using AiFrame.InterfaceLib.MVP;

namespace AiFrame.Base.Core.MVP
{
    /// <summary>
    /// Manages all opened windows in the main application.
    /// </summary>
    public class TabSetManager : IWindowManager<IWindow>, IObserver
    {
        private static TabSetManager pInstance;
        private IMainWindowView _mainWindowView;
        private ObservableCollection<IWindow> _windowCollection;
        private IWindow _activeWindow;

        /// <summary>
        /// Returns the instance.
        /// </summary>
        /// <returns></returns>
        public static TabSetManager Instance()
        {
            /* Überprüfen, ob es schon eine Instanz gibt.
             * Wenn nicht, soll eine erzeugt werden. */
            if (pInstance == null)
            {
                pInstance = new TabSetManager();
            }
            return pInstance;
        }

        /// <summary>
        /// Brings a window to front.
        /// </summary>
        /// <param name="window">The window.</param>
        private void BringWindowToFront(IWindow window)
        {
            OnActiveWindowChanges(window);
            window.BringWindowToFront();

            /* Als aktuelles Fenster abspeichern */
            //_activeWindow = window;
            OnActiveWindowChanged(window);
        }

        /// <summary>
        /// Initialisiert den TabSetManager.
        /// Muss aufgerufen werden, bevor Fenster angezeigt werden können.
        /// </summary>
        public void Initialize(IMainWindowView mainWindowView)
        {
            _mainWindowView = mainWindowView;
        }

        /// <summary>
        /// Der Standard-Konstruktor soll aufgrund des Singleton-Musters
        /// nach außen hin nicht sichtbar sein.
        /// </summary>
        private TabSetManager()
        {
            _windowCollection = new ObservableCollection<IWindow>();
            _windowCollection.RegisterObserver(this);
        }

        #region Implementation of IWindowManager

        public void RegisterWindow(IWindow window)
        {
            if (_mainWindowView == null)
                throw new MissingInitialisationException();
            
            _windowCollection.Add(window);
            BringWindowToFront(window);
            window.RefreshView();
            
        }

        public void CloseWindow(IWindow window)
        {
            _windowCollection.Remove(window);
            window.SetParentWindow(null);
            window.SetFree();
        }

        /// <summary>
        /// Gibt den Index eines Fensters, welches von einem bestimmten Typ ist,
        /// zurück.
        /// </summary>
        /// <typeparam name="W"></typeparam>
        /// <returns></returns>
        private int GetWindowTypeIndex<W>()
        {
            for (int i = 0; i < _windowCollection.Count; i++)
            {
                /* Falls der Typ existiert, true zurückgeben! */
                if (_windowCollection[i] is W)
                {
                    return i;
                }
            }
            return -1;
        }

        public bool ExistsWindow<W>()
        {
            if (GetWindowTypeIndex<W>() == -1)
                return false;

            return true;
        }

        public void BringWindowToFront<W>()
        {
            int index = GetWindowTypeIndex<W>();

            /* Falls das Fenster nicht in der Liste existiert, nichts tun.
             * Der Entwickler ist selbst dafür verantwortlich, vorher nachzuschauen,
             * ob es dieses Fenster auch gibt. */
            if (index != -1)
            {
//                OnActiveWindowChanges(_windowCollection[index]);
                BringWindowToFront(_windowCollection[index]);
//                OnActiveWindowChanged(_windowCollection[index]);
            }
        }

        public IWindow ActiveWindow
        {
            get { return _activeWindow; }
        }

        public event EventHandler<ActiveWindowChangedParams<IWindow>> ActiveWindowChanged;
        public event EventHandler<ActiveWindowChangedParams<IWindow>> ActiveWindowChanges;

        protected void OnActiveWindowChanged(IWindow window)
        {
            if (ActiveWindowChanged != null)
                ActiveWindowChanged(this, new ActiveWindowChangedParams<IWindow>(window));

            _activeWindow = window;
        }

        protected void OnActiveWindowChanges(IWindow window)
        {
            if (ActiveWindowChanges != null)
                ActiveWindowChanges(this, new ActiveWindowChangedParams<IWindow>(window));
            
        }

        #endregion

        public void NotifyChanges(object sender, object obj)
        {
            if (sender is ObservableCollection<IWindow>)
            {
                ObservableCollection<IWindow> oc =
                    (ObservableCollection<IWindow>) sender;
                
                /* Für jedes Fenster einen Tab erzeugen */
                foreach (IWindow wnd in oc)
                {
                    _mainWindowView.AddContainer(wnd);
                }
            }
        }

        #region Implementation of IShortCuts

        public void RefreshView()
        {
            /* Aktives Fenster auf null prüfen */
            if (_activeWindow != null)
                _activeWindow.RefreshView();
        }

        #endregion
    }
}